package team.hyznrj.studentsys.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import team.hyznrj.studentsys.constant.CookieConstant;
import team.hyznrj.studentsys.constant.RedisConstant;
import team.hyznrj.studentsys.dao.mapper.AccountInfoMapper;
import team.hyznrj.studentsys.dao.repository.account.AccountInfoRepository;
import team.hyznrj.studentsys.dao.repository.CollegeMajorRepository;
import team.hyznrj.studentsys.dto.ResultDto;
import team.hyznrj.studentsys.entity.account.AccountInfo;
import team.hyznrj.studentsys.entity.CollegeMajor;
import team.hyznrj.studentsys.enums.AccountEnum;
import team.hyznrj.studentsys.exception.AccountException;
import team.hyznrj.studentsys.form.AccountForm;
import team.hyznrj.studentsys.form.RegisterForm;
import team.hyznrj.studentsys.service.AccountInfoService;
import team.hyznrj.studentsys.utils.CookieUtil;
import team.hyznrj.studentsys.utils.KeyUtil;
import team.hyznrj.studentsys.utils.PasswordSecurity;
import team.hyznrj.studentsys.utils.RedisUtil;
import team.hyznrj.studentsys.utils.ResultUtil;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author ReMidDream
 * @date 2018-04-23 15:53
 **/
@Service
@Slf4j
public class AccountInfoServiceImpl implements AccountInfoService {
	private final AccountInfoRepository accountInfoRepository;
	private final CollegeMajorRepository collegeMajorRepository;
	private final AccountInfoMapper accountInfoMapper;
	private final RedisUtil redisUtil;
	@Autowired
	public AccountInfoServiceImpl(AccountInfoRepository accountInfoRepository,
			CollegeMajorRepository collegeMajorRepository, AccountInfoMapper accountInfoMapper, RedisUtil redisUtil) {
		this.accountInfoRepository = accountInfoRepository;
		this.collegeMajorRepository = collegeMajorRepository;
		this.accountInfoMapper = accountInfoMapper;
		this.redisUtil = redisUtil;
	}

	@Override
	public ResultDto<?> login(AccountForm accountForm, HttpServletResponse response) {
		//2018-09-04：zzf:帐号认证已由controller shiro框架进行认证
		//此处进行了细小的修改
		String username = accountForm.getUserAccount();
		String saltPsw=PasswordSecurity.getMD5(accountForm.getUserPassword(), username+"#");
		System.out.println("password:"+saltPsw);
		/*
		 * 登录认证
		 */
		AccountInfo account = accountInfoRepository.findByUserAccount(accountForm.getUserAccount());
		if (account == null) {
			log.error(" @登录 : 帐号错误,account={}", accountForm);
			throw new AccountException(AccountEnum.ACCOUNT_PASSWORD_NOT_CORRECT);
		}
		if (!account.getUserPassword().equals(saltPsw)) {
			log.error(" @登录 : 密码错误,account={}", accountForm);
			throw new AccountException(AccountEnum.ACCOUNT_PASSWORD_NOT_CORRECT);
		}
		
		
		// 生成 token
		String token = UUID.randomUUID().toString();
		// 设置 帐号登录有效时间为 2小时
		Integer expire = RedisConstant.EXPIRE;
		// token作为key 帐号信息作为value 放入 redis
		redisUtil.setAccount(token, account, expire);
		// token到Cookie
		CookieUtil.set(response, CookieConstant.TOKEN, token, expire);
		return ResultUtil.Success();
	}

	@Override
	public ResultDto<?> logout(HttpServletRequest request, HttpServletResponse response) {

		// 查询Cookie
		Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
		if (cookie != null) {
			// 清除redis
			redisUtil.clearAccount(cookie);
			// 清除Cookie
			CookieUtil.set(response, CookieConstant.TOKEN, null, 0);
		}
		return ResultUtil.Success();
	}

	@Override
	public ResultDto<?> registerAccount(RegisterForm registerForm) {

		AccountInfo existAccount = accountInfoRepository.findByUserAccount(registerForm.getUserAccount());

		if (existAccount != null) {
			log.error(" @注册帐号 : 帐号已存在, UserAccount={}", registerForm.getUserAccount());
			throw new AccountException(AccountEnum.ACCOUNT_IS_EXIST);
		}

		AccountInfo accountInfo = new AccountInfo();
		// todo 密码 加盐
		String psw=PasswordSecurity.getMD5(registerForm.getUserPassword(), registerForm.getUserAccount()+"#");
		registerForm.setUserPassword(psw);
		// 给 college_major_id 赋值
		if (registerForm.getCollegeId() != null) {
			/*
			 * 判断是否为院管理
			 */
			if (registerForm.getMajorId() == null) {
				// 判断是否存在学院
				if (collegeMajorRepository.findOne(registerForm.getCollegeId()) != null) {
					accountInfo.setCollegeMajorId(registerForm.getCollegeId());
				} else {
					log.error(" @注册帐号 : 学院/专业编号有误");
					throw new AccountException(AccountEnum.COLLEGE_MAJOR_PARAM_ERROR);
				}
			} else {
				/*
				 * 系管理
				 */
				// 判断是否存在此专业
				if (collegeMajorRepository.findOne(registerForm.getMajorId()) != null) {
					// 判断是否存在专业隶属的学院
					if (collegeMajorRepository.findOne(registerForm.getCollegeId()) != null) {
						accountInfo.setCollegeMajorId(registerForm.getMajorId());
					} else {
						log.error(" @注册帐号 : 学院/专业编号有误");
						throw new AccountException(AccountEnum.COLLEGE_MAJOR_PARAM_ERROR);
					}
				} else {
					log.error(" @注册帐号 : 学院/专业编号有误");
					throw new AccountException(AccountEnum.COLLEGE_MAJOR_PARAM_ERROR);
				}
			}

		} else {
			if (registerForm.getMajorId() == null) {
				// 超级管理员
				accountInfo.setCollegeMajorId("iAmsSuperAdmin");
			} else {
				log.error(" @注册帐号 : 学院/专业编号有误");
				throw new AccountException(AccountEnum.COLLEGE_MAJOR_PARAM_ERROR);
			}
		}

		BeanUtils.copyProperties(registerForm, accountInfo);

		accountInfo.setId(KeyUtil.getUniqueKey());
		log.info("注册帐号到数据库!");
		accountInfoRepository.save(accountInfo);
		return ResultUtil.Success();
	}

	@Override
	@Transactional
	public ResultDto deleteAccount(List<String> accountIds) {
		for (String id : accountIds) {
			accountInfoRepository.delete(id);
		}
		return ResultUtil.Success();
	}

	@Override
	public ResultDto<?> findByAccountInfo(String token) {

		AccountInfo account = redisUtil.getAccount(token);

		String collegeMajorId = account.getCollegeMajorId();

		if (collegeMajorId == null) {
			throw new RuntimeException();
		}

		List<AccountInfo> accountInfoList = accountInfoRepository.findByCollegeMajorId(collegeMajorId);

		/*
		 * 院管理 返回 自己 + 院宿系管理
		 */
		if (accountInfoList.size() == 1) {
			List<CollegeMajor> childMajor = collegeMajorRepository
					.findByParentId(accountInfoList.get(0).getCollegeMajorId());

			// 排除只存在一个 系管理 的情况
			if (childMajor.size() == 0) {
				return ResultUtil.Success(accountInfoList);
			}

			Set<String> childMajorIds = childMajor.stream().map(CollegeMajor::getId).collect(Collectors.toSet());
			accountInfoList.addAll(accountInfoMapper.findByCollegeMajorId(childMajorIds));
		}

		/*
		 * 系管理返回自己
		 */
		return ResultUtil.Success(accountInfoList);
	}

	@Override
	public ResultDto<?> updateAccountInfo(AccountForm accountForm) {
		String saltPsw=PasswordSecurity.getMD5(accountForm.getUserPassword(), accountForm.getUserAccount()+"#");
		AccountInfo account = accountInfoRepository.findByUserAccount(accountForm.getUserAccount());
		account.setUserPassword(saltPsw);
		log.info("更新密码到数据库!");
		AccountInfo save = accountInfoRepository.save(account);
		return ResultUtil.Success(save);
	}

}
